package service

import (
	"context"
	"encoding/json"
	"github.com/go-kratos/kratos/v2/log"
	"github.com/go-kratos/kratos/v2/transport/http"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/trace"
	recover_v1 "kratosRecoverPanic/api/recover/v1"
	"kratosRecoverPanic/internal/biz"
	"kratosRecoverPanic/pkg/gconv"
	"kratosRecoverPanic/pkg/kratos_encoder"
)

// recover服务的Service
type RecoverService struct {
	recover_v1.UnimplementedRecoverServer

	log        *log.Helper
	recoverBiz *biz.RecoverBiz
}

func NewRecoverService(recoverBiz *biz.RecoverBiz, logger log.Logger) *RecoverService {
	return &RecoverService{
		log:        log.NewHelper(logger),
		recoverBiz: recoverBiz,
	}
}

func (r *RecoverService) KratosRecover(ctx context.Context, req *recover_v1.KratosRecoverReq) (ret *recover_v1.KratosRecoverReply, errRet error) {
	ctx, span := otel.Tracer("Service").Start(ctx, "KratosRecoverService", trace.WithSpanKind(trace.SpanKindProducer))
	defer func() {
		// 在每个service层主动recover业务代码中的panic
		// 优点: 可以灵活设置log、trace
		// 缺点: 每个service都需要写一次(也就麻烦一点点)
		//if err := recover(); err != nil {
		//	// trace
		//	stackInfo := string(debug.Stack())
		//	span.SetAttributes(attribute.String("errStack", stackInfo))
		//	// log
		//	errMsg := fmt.Sprintf("%v方法中发生了panic errStack: %v", "KratosRecoverService", stackInfo)
		//	r.log.WithContext(ctx).Error(errMsg)
		//	// Notice 在业务代码中发生了 panic 后，根据再Error响应中加上捕获panic的标识！
		//	errRet = errors.New("业务中出现了-Internal Server Error!")
		//}
		span.End()
	}()

	// trace
	span.SetAttributes(attribute.String("req", gconv.String(req)))

	return r.recoverBiz.KratosRecover(ctx, req)
}

// 单独注册的路由
func (r *RecoverService) KratosSingleHandler(w http.ResponseWriter, c *http.Request) {
	// Notice 需要单独写recover panic
	defer func() {
		if err := recover(); err != nil {
			errStr, _ := json.Marshal(kratos_encoder.Response{
				Code:       500,
				Reason:     "single-handler Internal Server Error!",
				Message:    nil,
				ServerTime: 0,
				TraceId:    "",
			})
			w.Write(gconv.Bytes(errStr))
			return
		}
	}()

	panic("single-handler")

	retStr, _ := json.Marshal(kratos_encoder.Response{
		Code:       200,
		Reason:     "单独注册的路由!",
		Message:    nil,
		ServerTime: 0,
		TraceId:    "",
	})
	w.Write(gconv.Bytes(retStr))

}
